package run.siyuan.poi.policy;

import cn.hutool.core.util.ObjectUtil;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.data.TextRenderData;
import com.deepoove.poi.exception.RenderException;
import com.deepoove.poi.plugin.table.LoopColumnTableRenderPolicy;
import com.deepoove.poi.render.compute.EnvModel;
import com.deepoove.poi.render.compute.RenderDataCompute;
import com.deepoove.poi.render.processor.DocumentProcessor;
import com.deepoove.poi.render.processor.EnvIterator;
import com.deepoove.poi.resolver.TemplateResolver;
import com.deepoove.poi.template.ElementTemplate;
import com.deepoove.poi.template.MetaTemplate;
import com.deepoove.poi.template.run.RunTemplate;
import com.deepoove.poi.util.ReflectionUtils;
import com.deepoove.poi.util.TableTools;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlObject;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRow;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVMerge;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description
 * @Author admin
 */
public class DefineMethodPolicy extends LoopColumnTableRenderPolicy {
    private String prefix;
    private String suffix;
    private boolean onSameLine;
    private int rowIndex;
    private String fieldName;

    private Integer templateRowStartIndex;


    public DefineMethodPolicy() {
        this(false);
    }

    public DefineMethodPolicy(boolean onSameLine) {
        this("[", "]", onSameLine);
    }

    public DefineMethodPolicy(String prefix, String suffix) {
        this(prefix, suffix, false);
    }

    public DefineMethodPolicy(String prefix, String suffix, boolean onSameLine) {
        this.prefix = prefix;
        this.suffix = suffix;
        this.onSameLine = onSameLine;
    }

    public void render(ElementTemplate eleTemplate, Object data, XWPFTemplate template) {
        if (data == null) {
            return;
        }
        RunTemplate runTemplate = (RunTemplate) eleTemplate;
        XWPFRun run = runTemplate.getRun();

        if (!TableTools.isInsideTable(run)) {
            throw new IllegalStateException("The template tag " + runTemplate.getSource() + " must be inside a table");
        } else {
            XWPFTableCell tagCell = (XWPFTableCell) ((XWPFParagraph) run.getParent()).getBody();
            XWPFTable table = tagCell.getTableRow().getTable();
            run.setText("", 0);
            int templateRowIndex = this.getTemplateRowIndex(tagCell);
            this.templateRowStartIndex = templateRowIndex;
            if (null != data && data instanceof Iterable) {
                Iterator<?> iterator = ((Iterable) data).iterator();
                XWPFTableRow templateRow = table.getRow(templateRowIndex);
                TemplateResolver resolver = null;
                try {
                    resolver = new TemplateResolver(template.getConfig().copy(this.prefix, this.suffix));
                } catch (CloneNotSupportedException e) {
                    throw new RuntimeException(e);
                }
                boolean firstFlag = true;
                int index = 0;
                boolean hasNext = iterator.hasNext();

                while (hasNext) {
                    Object root = iterator.next();
                    hasNext = iterator.hasNext();
                    int insertPosition = templateRowIndex++;
                    table.insertNewTableRow(insertPosition);
                    this.setTableRow(table, templateRow, insertPosition);
                    XmlCursor newCursor = templateRow.getCtRow().newCursor();
                    newCursor.toPrevSibling();
                    XmlObject object = newCursor.getObject();
                    XWPFTableRow nextRow = new XWPFTableRow((CTRow) object, table);
                    if (!firstFlag) {
                        List<XWPFTableCell> tableCells = nextRow.getTableCells();
                        Iterator var21 = tableCells.iterator();

                        while (var21.hasNext()) {
                            XWPFTableCell cell = (XWPFTableCell) var21.next();
                            CTTcPr tcPr = TableTools.getTcPr(cell);
                            CTVMerge vMerge = tcPr.getVMerge();
                            if (null != vMerge && STMerge.RESTART == vMerge.getVal()) {
                                vMerge.setVal(STMerge.CONTINUE);
                            }
                        }
                    } else {
                        firstFlag = false;
                    }

                    this.setTableRow(table, nextRow, insertPosition);
                    RenderDataCompute dataCompute = template.getConfig().getRenderDataComputeFactory().newCompute(EnvModel.of(root, EnvIterator.makeEnv(index++, hasNext)));
                    List<XWPFTableCell> cells = nextRow.getTableCells();
                    TemplateResolver finalResolver = resolver;
                    cells.forEach((cellx) -> {
                        List<MetaTemplate> templates = finalResolver.resolveBodyElements(cellx.getBodyElements());
                        (new DocumentProcessor(template, finalResolver, dataCompute)).process(templates);
                    });
                }
            }

            table.removeRow(templateRowIndex);
            this.afterloop(table, data);
        }
    }

    private int getTemplateRowIndex(XWPFTableCell tagCell) {
        XWPFTableRow tagRow = tagCell.getTableRow();
        return this.onSameLine ? this.getRowIndex(tagRow) : this.getRowIndex(tagRow) + 1;
    }

    protected void afterloop(XWPFTable table, Object data) {
        if (ObjectUtil.isEmpty(data)) {
            return;
        }
        // 表格转换为二位数组
        int size = ((List) data).size();
        int rowSize = size;
        int cellSize = table.getRows().get(templateRowStartIndex).getTableCells().size();
        String[][] array = new String[rowSize][cellSize];

        List<XWPFTableRow> rows = table.getRows();
        for (int i = 0; i < size; i++) {
            XWPFTableRow tableRow = rows.get(templateRowStartIndex + i);
            // 列
            List<XWPFTableCell> tableCells = tableRow.getTableCells();
            for (int j = 0; j < tableCells.size(); j++) {
                array[i][j] = tableCells.get(j).getText();
            }
        }

        Integer mergerRowStartIndex = null;
        Integer mergerRowEndIndex = null;
        Integer removerCellNumber = 0;
        // 判断行是否存在相同元素
        for (int i = 0; i < array.length; i++) {
            // 行内元素比较
            for (int j = 0; j < array[i].length - 1; j++) {
                String var1 = array[i][j];
                for (int k = j + 1; k < array[i].length; k++) {
                    String var2 = array[i][k];
                    // 元素不相等
                    if (!var1.equals(var2)) {
                        // 不相等直接结束循环，因为不需要合并
                        j = k - 1;
                        break;
                    }
                    // 记录下标
                    mergerRowStartIndex = j;
                    mergerRowEndIndex = k;
                    // 单元格最后一个，循环下一行
                    if (mergerRowEndIndex == array[i].length - 1) {
                        j = k;
                    }
                }
                System.out.println("mergerRowStartIndex = " + mergerRowStartIndex + ",mergerRowEndIndex = " + mergerRowEndIndex + ",removerCellNumber=" + removerCellNumber);
                // 合并
                if (ObjectUtil.isNotEmpty(mergerRowStartIndex) && ObjectUtil.isNotEmpty(mergerRowEndIndex)) {
                    int a = mergerRowStartIndex - removerCellNumber;
                    int b = mergerRowEndIndex - removerCellNumber;
                    System.out.println("i = " + i + ",j = " + j);
                    System.out.println("a = " + a + ",b = " + b);
                    // 水平合并
                    TableTools.mergeCellsHorizonal(table, templateRowStartIndex + i, a, b);
                    removerCellNumber = removerCellNumber + mergerRowEndIndex - mergerRowStartIndex;
                    mergerRowStartIndex = null;
                    mergerRowEndIndex = null;
//                    break;
                }
            }
            removerCellNumber = 0;
        }


    }

    private void setTableRow(XWPFTable table, XWPFTableRow templateRow, int pos) {
        List<XWPFTableRow> rows = (List) ReflectionUtils.getValue("tableRows", table);
        rows.set(pos, templateRow);
        table.getCTTbl().setTrArray(pos, templateRow.getCtRow());
    }

    private int getRowIndex(XWPFTableRow row) {
        List<XWPFTableRow> rows = row.getTable().getRows();
        return rows.indexOf(row);
    }


    /**
     * 合并行
     *
     * @param rowIndex 列
     * @param index    重复行下标
     * @param count    重复数量
     */
    private void mergeCellsVertically(XWPFTable table, int rowIndex, int index, int count) {
        if (count > 1) {
            TableTools.mergeCellsVertically(table, rowIndex, index - count + 1, index);
        }
    }

    private void mergeCellsVertically(XWPFTable table, int rowIndex, List<LinkedHashMap<String, Object>> list, int count) {
        if (count > 1) {
            TableTools.mergeCellsVertically(table, rowIndex, list.size() - count + 1, list.size());
        }
    }

    /**
     * 获取值，判断是重复
     *
     * @param target    数据源
     * @param fieldName 字段名
     * @return 值
     */
    public String getFieldValue(Object target, String fieldName) {
        try {
            if (target instanceof Map) {
                return ((Map<?, ?>) target).get(fieldName).toString();
            }

            Object HSSFCell = FieldUtils.readField(target, fieldName, true);
            if (HSSFCell instanceof String) {
                return (String) HSSFCell;
            }
            TextRenderData textRenderData = (TextRenderData) HSSFCell;
            return textRenderData.getText();
        } catch (IllegalAccessException e) {
            throw new RuntimeException("字段类型不匹配，请检查字段类型和实体类是否一致");
        }
    }


}
